#include"protocolswitcher.h"

ProtocolSwitcher::ProtocolSwitcher(QWidget *parent)
    : QWidget(parent),
      udpSocket(nullptr),
      tcpSocket(nullptr)
{
    // UI Setup
    QVBoxLayout *layout = new QVBoxLayout(this);

    protocolComboBox = new QComboBox();
    protocolComboBox->addItem("UDP Unicast");
    protocolComboBox->addItem("UDP Multicast");
    protocolComboBox->addItem("UDP Broadcast");
    protocolComboBox->addItem("TCP");

    sendButton = new QPushButton("Send Message");

    checkbox = new QCheckBox("存盘");
    cycleCheckbox = new QCheckBox("循环");
    QHBoxLayout *Hlayout = new QHBoxLayout;
    Hlayout->addWidget(checkbox);
    Hlayout->addWidget(cycleCheckbox);

    sendTextEdit = new QTextEdit();
    sendSourTextEdit = new QTextEdit();
    outputTextEdit = new QTextEdit();

    outputTextEdit->setReadOnly(true);
    layout->addWidget(protocolComboBox);
    layout->addWidget(sendButton);
    layout->addLayout(Hlayout);
    layout->addWidget(sendTextEdit);
    layout->addWidget(sendSourTextEdit);
    layout->addWidget(outputTextEdit);

    // Connections
    connect(protocolComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onProtocolChanged(int)));
    connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendMessage()));
    connect(checkbox, &QCheckBox::toggled, this, &ProtocolSwitcher::onCheckBoxToggled);
    connect(cycleCheckbox, &QCheckBox::toggled, this, &ProtocolSwitcher::onCycleCheckboxToggled);

    TimerExample();
    // Default to UDP Unicast
    loadConfigFromXml("config.xml");
    onProtocolChanged(0);
    resize(500,600);
}

void ProtocolSwitcher::onProtocolChanged(int index)
{
    // Clean up old sockets
    if (udpSocket)
    {
        udpSocket->close();
        delete udpSocket;
        udpSocket = nullptr;
    }
    if (tcpSocket)
    {
        tcpSocket->disconnectFromHost();
        tcpSocket->close();
        delete tcpSocket;
        tcpSocket = nullptr;
    }

    // Set the selected protocol
    if (index == 0) // UDP Unicast
    {
        udpSocket = new QUdpSocket(this);
                   udpSocket->bind(QHostAddress::Any,udpB_softUnicastPort);
        connect(udpSocket, SIGNAL(readyRead()), this, SLOT(onUdpDataReceived()));
        outputTextEdit->append("Switched to UDP Unicast.");
    }
    else if (index == 1) // UDP Multicast
    {
        udpSocket = new QUdpSocket(this);
        // Bind to IPv4 address, and then join multicast group
        if (udpSocket->bind(QHostAddress::AnyIPv4, udpB_softMulticastPort, QUdpSocket::ShareAddress)) {
            udpSocket->joinMulticastGroup(QHostAddress(udpB_softMulticastHost)); // Example multicast address
            connect(udpSocket, SIGNAL(readyRead()), this, SLOT(onUdpDataReceived()));
            outputTextEdit->append("Switched to UDP Multicast.");
        } else {
            outputTextEdit->append("Failed to bind UDP socket for Multicast.");
        }
    }
    else if (index == 2) // UDP Broadcast
    {
        udpSocket = new QUdpSocket(this);
        if (udpSocket->bind(QHostAddress::AnyIPv4, udpB_softBroadcastPort, QUdpSocket::ShareAddress)) {
            connect(udpSocket, SIGNAL(readyRead()), this, SLOT(onUdpDataReceived()));
            outputTextEdit->append("Switched to UDP Broadcast.");
        } else {
            outputTextEdit->append("Failed to bind UDP socket for Broadcast.");
        }
    }
    else if (index == 3) // TCP
    {
        //            tcpSocket = new QTcpSocket(this);
        //            tcpServer = new QTcpServer(this);
        //            tcpServer->listen(QHostAddress::Any,8010);
        //            connect(tcpSocket, &QTcpSocket::readyRead, this, &ProtocolSwitcher::onTcpDataReceived);
        //            connect(tcpServer, &QTcpServer::newConnection, this, &ProtocolSwitcher::onTcpConnected);
        //            connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
        //                            this, SLOT(onTcpError(QAbstractSocket::SocketError)));  // 使用传统信号槽连接方式
        //            tcpSocket->connectToHost("192.168.3.12", 12345);
        //            outputTextEdit->append("Connecting to TCP server...");
        tcpSocket = new QTcpSocket(this);
        tcpSocket->connectToHost("127.0.0.1", tcpPort);  // 连接到本机服务器（127.0.0.1）端口12345
        //connect(tcpServer, &QTcpServer::newConnection, this, &ProtocolSwitcher::onTcpConnected);
        connect(tcpSocket, &QTcpSocket::readyRead, this, &ProtocolSwitcher::onTcpDataReceived);
        connect(tcpSocket, &QTcpSocket::connected, this, &ProtocolSwitcher::onTcpConnected);
    }
}

void ProtocolSwitcher::onSendMessage()
{//       // 初始化结构体并填充数据
    // 将结构体数据转为 QByteArray

    Data data;
    data.head = 0xEB90;
    data.tail = 0x0D0A;
    data.type = 0;  // 可以根据需要初始化其他成员
    data.dataType = 0;  // 根据需要初始化

    QString msg = sendTextEdit->toPlainText();
    data.info = msg;

    // 计算 data.message 的长度
    data.dataLong = data.info.length();

//    QByteArray message((const char*)&data, sizeof(data));
    // 将结构体的内容转换为 QByteArray 进行发送
    QByteArray message;
//    QDataStream stream(&message, QIODevice::WriteOnly);
//    stream << data.head
//           << data.type
//           << data.dataType
//           << data.dataLong
//           << data.info
//           << data.tail;
    message.append(reinterpret_cast<const char*>(&data.head), sizeof(data.head));
    message.append(reinterpret_cast<const char*>(&data.type), sizeof(data.type));
    message.append(reinterpret_cast<const char*>(&data.dataType), sizeof(data.dataType));
    message.append(reinterpret_cast<const char*>(&data.dataLong), sizeof(data.dataLong));
    message.append(data.info.toUtf8());  // 确保按 UTF-8 编码加入字符串
    message.append(reinterpret_cast<const char*>(&data.tail), sizeof(data.tail));
    sendData(message);
}
void ProtocolSwitcher::sendData(QByteArray message)
{
    if (protocolComboBox->currentIndex() == 0) // UDP Unicast
    {
        // Send UDP Unicast message
        //QByteArray message = "Hello from UDP Unicast!";
        udpSocket->writeDatagram(message, QHostAddress(udpA_softUnicastHost), udpA_softUnicastPort);
        sendSourTextEdit->append("Sent UDP Unicast message: ");
    }
    else if (protocolComboBox->currentIndex() == 1) // UDP Multicast
    {
        // Send UDP Multicast message
        //QByteArray message = "Hello from UDP Multicast!";
        udpSocket->writeDatagram(message, QHostAddress(udpA_softMulticastHost), udpA_softMulticastPort); // Multicast address
        sendSourTextEdit->append("Sent UDP Multicast message: ");
    }
    else if (protocolComboBox->currentIndex() == 2) // UDP Broadcast
    {
        // Send UDP Broadcast message
        //QByteArray message = "Hello from UDP Broadcast!";
        udpSocket->writeDatagram(message, QHostAddress::Broadcast, udpA_softBroadcastPort);
        sendSourTextEdit->append("Sent UDP Broadcast message: ");
    }
    else if (protocolComboBox->currentIndex() == 3) // TCP
    {
        // Send TCP message (only after connected)
        if (tcpSocket->state() == QTcpSocket::ConnectedState)
        {
            //QByteArray message = "Hello from TCP!";
            tcpSocket->write(message);
            sendSourTextEdit->append("Sent TCP message: ");
        }
        else
        {
            sendSourTextEdit->append("TCP is not connected yet.");
        }
    }
}
void ProtocolSwitcher::judgeSaveState(QByteArray datagram)
{
    qDebug()<<1;
    if(static_cast<uint8_t>(datagram[2]) == static_cast<uint8_t>(1))
    {
        qDebug()<<2;
        // 屏蔽信号
        checkbox->blockSignals(true);

        checkbox->setChecked(!datagram[3]);
        // 恢复信号
        checkbox->blockSignals(false);
    }

}
void ProtocolSwitcher::recvState()
{
    State state;
    memset(&state, 0, sizeof(state));  // 清零整个结构体
    state.head=0XEB90;
    int save;
    if(checkbox->isChecked())
    {
        save=0;
    }
    else
    {
        save=1;
    }
    state.saveSta = save;
    state.tail=0X0D0A;
    QByteArray message;
    QDataStream stream(&message, QIODevice::WriteOnly);
    stream << state.head
           << state.type
           << state.saveSta
           << state.tail;


    sendData(message);

}

void ProtocolSwitcher::TimerExample() {
    // 创建定时器对象
    timer = new QTimer(this);

    // 设置定时器间隔为1秒(1000毫秒)
    timer->setInterval(1000);

    // 连接定时器的timeout信号到槽函数
    connect(timer, &QTimer::timeout, this, [&](){
        onSendMessage();
    });

}

void ProtocolSwitcher::saveFile(QByteArray datagram)
{
    Data datagramStruct;
    if (checkbox->isChecked()) {
        // 文件名
        QByteArray infoBytes1 = datagram.mid(6, datagram[4]);  // 取出从字节位置 6 开始，长度为 3 的字节
        datagramStruct.info = QString::fromUtf8(infoBytes1);  // 转换为字符串
        qDebug() << "Manual parsed info: " << datagramStruct.info;
        QString fileName = "file.txt";

        if (!fileName.isEmpty()) {
            // 打开文件进行追加写入
            QFile file(fileName);
            if (file.open(QIODevice::Append | QIODevice::Text)) {  // 使用 Append 模式
                QTextStream out(&file);
                // 写入数据到文件
                out << datagramStruct.info << "\n";  // 追加数据并换行
                qDebug() << "Saved info to file:" << datagramStruct.info;
                file.close(); // 关闭文件
            } else {
                QMessageBox::warning(this, "Error", "Unable to open file for writing.");
            }
        }
    }
}


void ProtocolSwitcher::onUdpDataReceived()
{
    while (udpSocket->hasPendingDatagrams())
    {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;
        udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
        outputTextEdit->append("Received UDP message: ");
                if(static_cast<uint8_t>(datagram[2]) == static_cast<uint8_t>(0))
                {
                    saveFile(datagram);
                }

        QString hexString;
        for (int i = 0; i < datagram.size(); ++i) {
            hexString += QString("0x%1 ").arg(static_cast<unsigned char>(datagram[i]), 2, 16, QLatin1Char('0')).toUpper();
        }
        qDebug() << "Received UDP packet (hex):" << hexString;
        // 输出十六进制字符串到 outputTextEdit
        outputTextEdit->append(hexString);
        judgeSaveState(datagram);
    }
    recvState();
}

void ProtocolSwitcher::onTcpDataReceived()
{
    QByteArray data = tcpSocket->readAll();
    outputTextEdit->append("Received TCP message: ");
    // 创建一个字符串，用于保存接收到的十六进制数据
    QString hexString;

    // 遍历接收到的每个字节，转换为十六进制
    for (int i = 0; i < data.size(); ++i) {
        // 将每个字节转换为 16 进制的字符串
        hexString.append(QString("0x%1 ").arg(static_cast<unsigned char>(data[i]), 2, 16, QChar('0')).toUpper());
    }
    // 将接收到的发送者信息和十六进制字符串添加到 QTextEdit 中
    outputTextEdit->append(hexString);
    saveFile(data);
    judgeSaveState(data);
    recvState();
}

void ProtocolSwitcher::onTcpConnected()
{
    outputTextEdit->append("TCP connected.");
}

void ProtocolSwitcher::onTcpError(QAbstractSocket::SocketError socketError)
{
    Q_UNUSED(socketError);
    outputTextEdit->append("TCP connection failed: " + tcpSocket->errorString());
}

void ProtocolSwitcher::onCheckBoxToggled(bool checked)
{
    State state;
    memset(&state, 0, sizeof(state));  // 清零整个结构体
    state.head=0XEB90;
    state.type=2;
    state.tail=0X0D0A;
    if (checked) {

        state.saveSta = 0;

    } else {
        state.saveSta = 1;

    }
    QByteArray message;
    QDataStream stream(&message, QIODevice::WriteOnly);
    stream << state.head
           << state.type
           << state.saveSta
           << state.tail;
    sendData(message);
}

void ProtocolSwitcher::onCycleCheckboxToggled(bool checked)
{
    if(checked)
    {
        // 启动定时器
        timer->start();
    }
    else
    {
        timer->stop();
    }
}
void ProtocolSwitcher::loadConfigFromXml(const QString &filePath)
{
    // 创建 QDomDocument 对象
    QDomDocument doc;
    QFile file(filePath);

    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "Failed to open file for reading.";
        return;
    }

    if (!doc.setContent(&file)) {
        qDebug() << "Failed to parse XML.";
        file.close();
        return;
    }
    file.close();

    // 获取根节点
    QDomElement root = doc.documentElement();
    QDomElement networkElement = root.firstChildElement("network");

    // 读取 udpA_softUnicast 配置
    QDomElement udpA_softUnicastElement = networkElement.firstChildElement("udpA_softUnicast");
    udpA_softUnicastHost = udpA_softUnicastElement.firstChildElement("host").text();
    int a=udpA_softUnicastElement.firstChildElement("port").text().toInt();
    udpA_softUnicastPort = a;

    // 读取 udpA_softMulticast 配置
    QDomElement udpA_softMulticastElement = networkElement.firstChildElement("udpA_softMulticast");
    udpA_softMulticastHost = udpA_softMulticastElement.firstChildElement("host").text();
    udpA_softMulticastPort = udpA_softMulticastElement.firstChildElement("port").text().toInt();

    // 读取 udpA_softBroadcast 配置
    QDomElement udpA_softBroadcastElement = networkElement.firstChildElement("udpA_softBroadcast");
    udpA_softBroadcastHost = udpA_softBroadcastElement.firstChildElement("host").text();
    udpA_softBroadcastPort = udpA_softBroadcastElement.firstChildElement("port").text().toInt();

    // 读取 udpB_softUnicast 配置
    QDomElement udpB_softUnicastElement = networkElement.firstChildElement("udpB_softUnicast");
    udpB_softUnicastHost = udpB_softUnicastElement.firstChildElement("host").text();
    udpB_softUnicastPort = udpB_softUnicastElement.firstChildElement("port").text().toInt();

    // 读取 udpB_softMulticast 配置
    QDomElement udpB_softMulticastElement = networkElement.firstChildElement("udpB_softMulticast");
    udpB_softMulticastHost = udpB_softMulticastElement.firstChildElement("host").text();
    udpB_softMulticastPort = udpB_softMulticastElement.firstChildElement("port").text().toInt();

    // 读取 udpB_softBroadcast 配置
    QDomElement udpB_softBroadcastElement = networkElement.firstChildElement("udpB_softBroadcast");
    udpB_softBroadcastHost = udpB_softBroadcastElement.firstChildElement("host").text();
    udpB_softBroadcastPort = udpB_softBroadcastElement.firstChildElement("port").text().toInt();

    QDomElement tcp = networkElement.firstChildElement("tcp");
    tcpHost = tcp.firstChildElement("host").text();
    tcpPort = tcp.firstChildElement("port").text().toInt();
    //    qDebug() << "XML configuration loaded from config.xml.";
}
